#include "doorbell_sound.h"

#define ES8311_I2C_PORT I2C_NUM_0
#define I2C_SCL_PIN 1
#define I2C_SDA_PIN 0

#define I2S_MCK_PIN 3
#define I2S_BCK_PIN 2
#define I2S_DATA_WS_PIN 5
#define I2S_DATA_OUT_PIN 6
#define I2S_DATA_IN_PIN 4

#define PA_GPIO 46

/* i2c句柄 */
static i2c_master_bus_handle_t i2c_bus_handle;
static i2s_chan_handle_t       speakerHandle;
static i2s_chan_handle_t       micHandle;

static esp_codec_dev_sample_info_t fs;
static esp_codec_dev_handle_t      codec_dev;

static void doorbell_sound_I2CInit(void)
{
    i2c_master_bus_config_t i2c_bus_config      = {0};
    i2c_bus_config.clk_source                   = I2C_CLK_SRC_DEFAULT;
    i2c_bus_config.i2c_port                     = ES8311_I2C_PORT;
    i2c_bus_config.scl_io_num                   = I2C_SCL_PIN;
    i2c_bus_config.sda_io_num                   = I2C_SDA_PIN;
    i2c_bus_config.glitch_ignore_cnt            = 7;
    i2c_bus_config.flags.enable_internal_pullup = true;
    i2c_new_master_bus(&i2c_bus_config, &i2c_bus_handle);
}

static void doorbell_sound_I2SInit(void)
{
    /* i2s通道配置 : i2s_0  角色:主机或从机*/
    i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);

    i2s_std_config_t std_cfg = {
        .clk_cfg  = I2S_STD_CLK_DEFAULT_CONFIG(16000),                           /* 传入: 采样率 */
        .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(16, I2S_SLOT_MODE_MONO), /* 采样深度, 单声道  */
        .gpio_cfg = {
            .mclk = I2S_MCK_PIN,
            .bclk = I2S_BCK_PIN,
            .ws   = I2S_DATA_WS_PIN,
            .dout = I2S_DATA_OUT_PIN,
            .din  = I2S_DATA_IN_PIN,
        },
    };
    /* 创建通道 */
    i2s_new_channel(&chan_cfg, &speakerHandle, &micHandle);
    /* 初始化输出通道 */
    i2s_channel_init_std_mode(speakerHandle, &std_cfg);
    /* 初始化输入通道 */
    i2s_channel_init_std_mode(micHandle, &std_cfg);

    /* 使能输入和输出通道 */
    i2s_channel_enable(speakerHandle);
    i2s_channel_enable(micHandle);
}

static void doorbell_sound_ES8311Init(void)
{
    audio_codec_i2s_cfg_t i2s_cfg = {
        .rx_handle = micHandle,
        .tx_handle = speakerHandle,
    };
    /* 创建i2s数据接口 */
    const audio_codec_data_if_t *data_if = audio_codec_new_i2s_data(&i2s_cfg); /* 创建配置接口, 内部是通过i2c控制es8311 */

    /* 控制接口 */
    audio_codec_i2c_cfg_t i2c_cfg = {
        .addr       = ES8311_CODEC_DEFAULT_ADDR,
        .port       = ES8311_I2C_PORT,
        .bus_handle = i2c_bus_handle};
    const audio_codec_ctrl_if_t *out_ctrl_if = audio_codec_new_i2c_ctrl(&i2c_cfg);

    /* 创建gpio接口 */
    const audio_codec_gpio_if_t *gpio_if = audio_codec_new_gpio();

    /* 创建编解码器(es8311)接口 */
    es8311_codec_cfg_t es8311_cfg = {
        .codec_mode  = ESP_CODEC_DEV_WORK_MODE_BOTH, /* 编解码器的模式: 录音和播放 */
        .ctrl_if     = out_ctrl_if,                  /* 控制接口 */
        .gpio_if     = gpio_if,                      /* gpio接口 */
        .pa_pin      = PA_GPIO,                      /* pa引脚 */
        .use_mclk    = true,                         /* 使用主时钟 */
        .digital_mic = false                         /* 是否使用数字麦克风 */
    };
    const audio_codec_if_t *out_codec_if = es8311_codec_new(&es8311_cfg);

    /* 获取es8311设备的句柄, 将来通过这个句柄来读写音频数据 */
    esp_codec_dev_cfg_t dev_cfg = {
        .codec_if = out_codec_if,               // 编解码器接口
        .data_if  = data_if,                    // 数据接口
        .dev_type = ESP_CODEC_DEV_TYPE_IN_OUT   // 设备类型; 支持播放和录音
    };
    /* 创建3s8311设备 */
    codec_dev = esp_codec_dev_new(&dev_cfg);

    /* 对es8311做一些其他配置: 设置输出音量 */
    esp_codec_dev_set_out_vol(codec_dev, 70.0);

    /* 设置设备的采样信息 */
    fs.sample_rate     = 16000; /*  采样率 */
    fs.bits_per_sample = 16;    /* 采样深度 */
    fs.channel         = 1;     /* 声道: 1 */
    fs.channel_mask    = ESP_CODEC_DEV_MAKE_CHANNEL_MASK(0);

    /* 设置mic的增益: 增大录制的声音 */
    esp_codec_dev_set_in_gain(codec_dev, 50.0);
}

void doorbell_sound_Init(void)
{
    /* 1. i2c的初始化 */
    doorbell_sound_I2CInit();

    /* 2. i2s的初始化 */
    doorbell_sound_I2SInit();

    /* 3. 配置芯片: es8311 */
    doorbell_sound_ES8311Init();
}

void doorbell_sound_Open(void)
{

    /* 打开设备 */
    esp_codec_dev_open(codec_dev, &fs);
}

void doorbell_sound_Close(void)
{

    /* 打开设备 */
    esp_codec_dev_close(codec_dev);
}

/**
 * @description: 读取mic的数据
 * @param {uint8_t} *data 读取到的数据
 * @param {uint16_t} dataLen 读取的数据长度
 * @return {*}    ESP_CODEC_DEV_OK: Read success
 *                ESP_CODEC_DEV_INVALID_ARG: Invalid arguments
 *                ESP_CODEC_DEV_NOT_SUPPORT: Codec not support
 *                ESP_CODEC_DEV_WRONG_STATE: Driver not open yet
 *                ESP_CODEC_DEV_READ_FAIL
 */
int doorbell_sound_ReadData(uint8_t *data, int dataLen)
{
    if(codec_dev && data && dataLen)
    {
        return esp_codec_dev_read(codec_dev, data, dataLen);
    }
    return ESP_CODEC_DEV_READ_FAIL;
}

/**
 * @description: 向es8311写数据
 * @param {uint8_t} *data 要写入的数据
 * @param {int} dataLen 要写入的数据长度
 * @return {*} ESP_CODEC_DEV_OK: Read success
 *                ESP_CODEC_DEV_INVALID_ARG: Invalid arguments
 *                ESP_CODEC_DEV_NOT_SUPPORT: Codec not support
 *                ESP_CODEC_DEV_WRONG_STATE: Driver not open yet
 *                ESP_CODEC_DEV_READ_FAIL
 */
int doorbell_sound_WriteData(uint8_t *data, int dataLen)
{
    if(codec_dev && data && dataLen)
    {
        return esp_codec_dev_write(codec_dev, data, dataLen);
    }
    return ESP_CODEC_DEV_WRITE_FAIL;
}
